using System;
using System.Web;
using System.Web.Handlers;
using Castle.Facilities.NHibernateIntegration;
using Castle.Windsor;
using NHibernate;

namespace Yama.MVC.NHibernate.Connections
{
    public class SessionWebModule : IHttpModule
    {
        /// <summary>
        /// http://markmail.org/message/wl7lvtzs5qmqrgsq
        /// </summary>
        protected static readonly String SessionKey = "SessionWebModule.session";

        /// <summary>
        /// Initializes a module and prepares it to handle requests.
        /// </summary>
        /// <param name="app">The app.</param>
        public void Init(HttpApplication app)
        {
            app.PreRequestHandlerExecute += OnBeginRequest;
            app.EndRequest += OnEndRequest;
        }

        /// <summary>
        /// Disposes of the resources (other than memory) used by the module that implements <see cref="T:System.Web.IHttpModule"/>.
        /// </summary>
        public void Dispose()
        {
        }

        private static void OnBeginRequest(object sender, EventArgs e)
        {
            HttpApplication ctx = (HttpApplication)sender;
            if (HandlerIsIrrelavant(ctx)) return;

            IWindsorContainer container = ObtainContainer();
            ISessionManager sessManager = (ISessionManager)container[typeof(ISessionManager)];
            HttpContext.Current.Items.Add(SessionKey, sessManager.OpenSession());
        }

        static private bool HandlerIsIrrelavant(HttpApplication ctx)
        {
            return ctx.Context.Handler is AssemblyResourceLoader || ctx.Context.Handler is DefaultHttpHandler;
        }

        private static void OnEndRequest(object sender, EventArgs e)
        {
            ISession session = (ISession)HttpContext.Current.Items[SessionKey];

            if (session != null)
            {
                session.Dispose();
            }
        }

        private static IWindsorContainer ObtainContainer()
        {
            IContainerAccessor containerAccessor =
                HttpContext.Current.ApplicationInstance as IContainerAccessor;

            if (containerAccessor == null)
            {
                throw new NullReferenceException("You must extend the HttpApplication in your web project " +
                                                 "and implement the IContainerAccessor to properly expose your container instance");
            }

            IWindsorContainer container = containerAccessor.Container;

            if (container == null)
            {
                throw new NullReferenceException("The container seems to be unavailable (null) in " +
                                                 "your HttpApplication subclass");
            }
            return container;
        }
    }
}